﻿using Group3.Framework.Exceptions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Group3.Framework.Extensions
{
    public static class ExtensionsDateTime
    {

        public static DateTime ToDateTime(this string value)
        {
            try
            {
                if (value.Length >= 14)
                    return DateTime.ParseExact(value, "yyyyMMddHHmmss", System.Globalization.CultureInfo.InvariantCulture);
                else if (value.Length >= 12)
                    return DateTime.ParseExact(value, "yyyyMMddHHmm", System.Globalization.CultureInfo.InvariantCulture);
                else if (value.Length >= 10)
                    return DateTime.ParseExact(value, "yyyyMMddHH", System.Globalization.CultureInfo.InvariantCulture);
                else if (value.Length >= 8)
                    return DateTime.ParseExact(value, "yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture);
                else if (value.Length >= 6)
                    return DateTime.ParseExact(value + "01", "yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture);
                else if (value.Length >= 4)
                    return DateTime.ParseExact(value + "0101", "yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture);
                else return DateTime.MinValue;

            }
            catch
            {
                throw new InvalidFormatException("Unexpected Date Time. Expected yyyyyMMddHHmm");
            }
            finally
            {

            }

        }
        public static string ToTwoDigitDateString(this DateTime value)
        {
            return value.ToString("dd.MM.yy");
        }
        public static string ToIsoDate(this DateTime value)
        {
            return value.toIsoDate("yyyyMMddHHmmss");
        }
        public static string ToIntervallString(this DateTime from, DateTime to)
        {
            bool ysame = from.Year == to.Year;
            bool monsame = from.Month == to.Month;
            bool daysame = from.Day == to.Day;
            string fmt = "dd.MM.yy HH:mm";
            string fmt1 = "";
            if (!ysame) fmt1 = "dd.MM.yy HH:mm";
            else if (!monsame) fmt1 = "dd.MM HH:mm";
            else if (!daysame) fmt1 = "dd HH:mm";
            else fmt1 = "HH:mm";
            return string.Format("{0:" + fmt + "} - {1:" + fmt1 + "}", from, to);
        }

        public static string IsoToMonthString(this string value)
        {
            List<string> months = new List<string>() { "Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez" };
            string month = value.SubstringValue(4, 2);
            int idx = -1;
            Int32.TryParse(month, out idx);
            if (idx < 0)
                return "ERROR";
            idx = idx - 1;
            string year = value.SubstringValue(2, 2);
            return string.Format("{0} {1}", months[idx], year);
        }
        private static string toIsoDate(this DateTime value, string format)
        {
            try
            {
                return value.ToString(format);
            }
            catch
            {
                return DateTime.MinValue.ToString(format);
            }
        }
        public static string ToIsoDateYYMMDD(this DateTime value)
        {
            return value.toIsoDate("yyyyMMdd");
        }
        public static string ToIsoDateYYMMDDHHMi(this DateTime value)
        {
            return value.toIsoDate("yyyyMMddHHmm");
        }
        public static DateTime MondayofWeek(this DateTime value)
        {
            switch (value.DayOfWeek)
            {
                case DayOfWeek.Monday:
                    return value;
                case DayOfWeek.Tuesday:
                    return value.AddDays(-1);
                case DayOfWeek.Wednesday:
                    return value.AddDays(-2);
                case DayOfWeek.Thursday:
                    return value.AddDays(-3);
                case DayOfWeek.Friday:
                    return value.AddDays(-4);
                case DayOfWeek.Saturday:
                    return value.AddDays(-5);
                case DayOfWeek.Sunday:
                    return value.AddDays(-6);
                default:
                    return value;
            }
        }
        public static string Week(this DateTime date)
        {
            int week, year;
            WeekOfDay(date, out week, out  year);
            return string.Format("{0:00}.{1}", week, year);
        }
        public static string SortWeek(this DateTime date)
        {
            int week, year;
            WeekOfDay(date, out week, out  year);
            return string.Format("{1}.{0:00}", week, year);
        }
        private static void WeekOfDay(DateTime day, out int week, out int year)
        {

            week = InternalWeek(day);
            year = day.Year;
            if (week == 53 && day.Month == 1)
                year = day.Year - 1;
            else if (week == 1 && day.Month == 12)
                year = day.Year + 1;
            else
                year = day.Year;
        }
        private static int InternalWeek(DateTime day)
        {
            bool thursdayflag = false;

            // Get the day number since the beginning of the year
            int dayofyear = day.DayOfYear;

            // Get the numeric weekday of the first day of the 
            // year (using sunday as FirstDay)
            int startweekdayofyear = (int)(new DateTime(day.Year, 1, 1).DayOfWeek);
            int endweekdayofyear = (int)(new DateTime(day.Year, 12, 31).DayOfWeek);
            // Compensate for the fact that we are using monday
            // as the first day of the week
            if (startweekdayofyear == 0) startweekdayofyear = 7;
            if (endweekdayofyear == 0) endweekdayofyear = 7;

            // Calculate the number of days in the first and last week
            int daysinfirstweek = 8 - startweekdayofyear;
            int daysinlastweek = 8 - endweekdayofyear;

            // If the year either starts or ends on a thursday it will have a 53rd week
            if (startweekdayofyear == 4 || endweekdayofyear == 4) thursdayflag = true;

            // We begin by calculating the number of FULL weeks between the start of the year and
            // our date. The number is rounded up, so the smallest possible value is 0.
            int fullweeks = (int)Math.Ceiling((dayofyear - daysinfirstweek) / 7.0);
            int weeknumber = fullweeks;

            // If the first week of the year has at least four days, then the actual week number for our date
            // can be incremented by one.
            if (daysinfirstweek >= 4) weeknumber += 1;

            //If week number is larger than week 52 (and the year doesn't either start or end on a thursday)
            // then the correct week number is 1. 
            if (weeknumber > 52 && !thursdayflag) weeknumber = 1;

            // If week number is still 0, it means that we are trying to evaluate the week number for a
            // week that belongs in the previous year (since that week has 3 days or less in our date's year).
            //We therefore make a recursive call using the last day of the previous year.
            if (weeknumber == 0) weeknumber = InternalWeek(new DateTime(day.Year - 1, 12, 31));
            return weeknumber;
        }
        public static DateTime Max(this DateTime date, DateTime otherdate)
        {
            if (date > otherdate)
                return date;
            else
                return otherdate;
        }
        public static DateTime Min(this DateTime date, DateTime otherdate)
        {
            if (date < otherdate)
                return date;
            else
                return otherdate;
        }

        public static TimeSpan Absolute(this TimeSpan span)
        {
            if (span.TotalMinutes < 0)
            {
                return new TimeSpan(span.Ticks * (-1));
            }
            return span;
        }
    }
}
